home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / zfileio.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  22.9 KB  |  969 lines

  1. /* Copyright (C) 1989, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: zfileio.c,v 1.9 2000/09/19 19:00:53 lpd Exp $ */
  20. /* File I/O operators */
  21. #include "memory_.h"
  22. #include "ghost.h"
  23. #include "gp.h"
  24. #include "oper.h"
  25. #include "stream.h"
  26. #include "files.h"
  27. #include "store.h"
  28. #include "strimpl.h"        /* for ifilter.h */
  29. #include "ifilter.h"        /* for procedure streams */
  30. #include "interp.h"        /* for gs_errorinfo_put_string */
  31. #include "gsmatrix.h"        /* for gxdevice.h */
  32. #include "gxdevice.h"
  33. #include "gxdevmem.h"
  34. #include "estack.h"
  35.  
  36. /* Forward references */
  37. private int write_string(P2(ref *, stream *));
  38. private int handle_read_status(P5(i_ctx_t *, int, const ref *, const uint *,
  39.                   op_proc_t));
  40. private int handle_write_status(P5(i_ctx_t *, int, const ref *, const uint *,
  41.                    op_proc_t));
  42.  
  43. /* ------ Operators ------ */
  44.  
  45. /* <file> closefile - */
  46. int
  47. zclosefile(i_ctx_t *i_ctx_p)
  48. {
  49.     os_ptr op = osp;
  50.     stream *s;
  51.  
  52.     check_type(*op, t_file);
  53.     if (file_is_valid(s, op)) {    /* closing a closed file is a no-op */
  54.     int status = sclose(s);
  55.  
  56.     if (status != 0 && status != EOFC) {
  57.         if (s_is_writing(s))
  58.         return handle_write_status(i_ctx_p, status, op, NULL,
  59.                        zclosefile);
  60.         else
  61.         return handle_read_status(i_ctx_p, status, op, NULL,
  62.                       zclosefile);
  63.     }
  64.     }
  65.     pop(1);
  66.     return 0;
  67. }
  68.  
  69. /* <file> read <int> -true- */
  70. /* <file> read -false- */
  71. private int
  72. zread(i_ctx_t *i_ctx_p)
  73. {
  74.     os_ptr op = osp;
  75.     stream *s;
  76.     int ch;
  77.  
  78.     check_read_file(s, op);
  79.     ch = sgetc(s);
  80.     if (ch >= 0) {
  81.     push(1);
  82.     make_int(op - 1, ch);
  83.     make_bool(op, 1);
  84.     } else if (ch == EOFC)
  85.     make_bool(op, 0);
  86.     else
  87.     return handle_read_status(i_ctx_p, ch, op, NULL, zread);
  88.     return 0;
  89. }
  90.  
  91. /* <file> <int> write - */
  92. int
  93. zwrite(i_ctx_t *i_ctx_p)
  94. {
  95.     os_ptr op = osp;
  96.     stream *s;
  97.     byte ch;
  98.     int status;
  99.  
  100.     check_write_file(s, op - 1);
  101.     check_type(*op, t_integer);
  102.     ch = (byte) op->value.intval;
  103.     status = sputc(s, (byte) ch);
  104.     if (status >= 0) {
  105.     pop(2);
  106.     return 0;
  107.     }
  108.     return handle_write_status(i_ctx_p, status, op - 1, NULL, zwrite);
  109. }
  110.  
  111. /* <file> <string> readhexstring <substring> <filled_bool> */
  112. private int zreadhexstring_continue(P1(i_ctx_t *));
  113.  
  114. /* We keep track of the odd digit in the next byte of the string */
  115. /* beyond the bytes already used.  (This is just for convenience; */
  116. /* we could do the same thing by passing 2 state parameters to the */
  117. /* continuation procedure instead of 1.) */
  118. private int
  119. zreadhexstring_at(i_ctx_t *i_ctx_p, os_ptr op, uint start)
  120. {
  121.     stream *s;
  122.     uint len, nread;
  123.     byte *str;
  124.     int odd;
  125.     stream_cursor_write cw;
  126.     int status;
  127.  
  128.     check_read_file(s, op - 1);
  129.     /*check_write_type(*op, t_string); *//* done by caller */
  130.     str = op->value.bytes;
  131.     len = r_size(op);
  132.     if (start < len) {
  133.     odd = str[start];
  134.     if (odd > 0xf)
  135.         odd = -1;
  136.     } else
  137.     odd = -1;
  138.     cw.ptr = str + start - 1;
  139.     cw.limit = str + len - 1;
  140.     for (;;) {
  141.     status = s_hex_process(&s->cursor.r, &cw, &odd,
  142.                    hex_ignore_garbage);
  143.     if (status == 1) {    /* filled the string */
  144.         ref_assign_inline(op - 1, op);
  145.         make_true(op);
  146.         return 0;
  147.     } else if (status != 0)    /* error or EOF */
  148.         break;
  149.     /* Didn't fill, keep going. */
  150.     status = spgetc(s);
  151.     if (status < 0)
  152.         break;
  153.     sputback(s);
  154.     }
  155.     nread = cw.ptr + 1 - str;
  156.     if (status != EOFC) {    /* Error */
  157.     if (nread < len)
  158.         str[nread] = (odd < 0 ? 0x10 : odd);
  159.     return handle_read_status(i_ctx_p, status, op - 1, &nread,
  160.                   zreadhexstring_continue);
  161.     }
  162.     /* Reached end-of-file before filling the string. */
  163.     /* Return an appropriate substring. */
  164.     ref_assign_inline(op - 1, op);
  165.     r_set_size(op - 1, nread);
  166.     make_false(op);
  167.     return 0;
  168. }
  169. private int
  170. zreadhexstring(i_ctx_t *i_ctx_p)
  171. {
  172.     os_ptr op = osp;
  173.  
  174.     check_write_type(*op, t_string);
  175.     if (r_size(op) > 0)
  176.     *op->value.bytes = 0x10;
  177.     return zreadhexstring_at(i_ctx_p, op, 0);
  178. }
  179. /* Continue a readhexstring operation after a callout. */
  180. /* *op is the index within the string. */
  181. private int
  182. zreadhexstring_continue(i_ctx_t *i_ctx_p)
  183. {
  184.     os_ptr op = osp;
  185.     int code;
  186.  
  187.     check_type(*op, t_integer);
  188.     if (op->value.intval < 0 || op->value.intval > r_size(op - 1))
  189.     return_error(e_rangecheck);
  190.     check_write_type(op[-1], t_string);
  191.     code = zreadhexstring_at(i_ctx_p, op - 1, (uint) op->value.intval);
  192.     if (code >= 0)
  193.     pop(1);
  194.     return code;
  195. }
  196.  
  197. /* <file> <string> writehexstring - */
  198. private int zwritehexstring_continue(P1(i_ctx_t *));
  199. private int
  200. zwritehexstring_at(i_ctx_t *i_ctx_p, os_ptr op, uint odd)
  201. {
  202.     register stream *s;
  203.     register byte ch;
  204.     register const byte *p;
  205.     register const char *const hex_digits = "0123456789abcdef";
  206.     register uint len;
  207.     int status;
  208.  
  209. #define MAX_HEX 128
  210.     byte buf[MAX_HEX];
  211.  
  212.     check_write_file(s, op - 1);
  213.     check_read_type(*op, t_string);
  214.     p = op->value.bytes;
  215.     len = r_size(op);
  216.     while (len) {
  217.     uint len1 = min(len, MAX_HEX / 2);
  218.     register byte *q = buf;
  219.     uint count = len1;
  220.     ref rbuf;
  221.  
  222.     do {
  223.         ch = *p++;
  224.         *q++ = hex_digits[ch >> 4];
  225.         *q++ = hex_digits[ch & 0xf];
  226.     }
  227.     while (--count);
  228.     r_set_size(&rbuf, (len1 << 1) - odd);
  229.     rbuf.value.bytes = buf + odd;
  230.     status = write_string(&rbuf, s);
  231.     switch (status) {
  232.         default:
  233.         return_error(e_ioerror);
  234.         case 0:
  235.         len -= len1;
  236.         odd = 0;
  237.         continue;
  238.         case INTC:
  239.         case CALLC:
  240.         count = rbuf.value.bytes - buf;
  241.         op->value.bytes += count >> 1;
  242.         r_set_size(op, len - (count >> 1));
  243.         count &= 1;
  244.         return handle_write_status(i_ctx_p, status, op - 1, &count,
  245.                        zwritehexstring_continue);
  246.     }
  247.     }
  248.     pop(2);
  249.     return 0;
  250. #undef MAX_HEX
  251. }
  252. private int
  253. zwritehexstring(i_ctx_t *i_ctx_p)
  254. {
  255.     os_ptr op = osp;
  256.  
  257.     return zwritehexstring_at(i_ctx_p, op, 0);
  258. }
  259. /* Continue a writehexstring operation after a callout. */
  260. /* *op is the odd/even hex digit flag for the first byte. */
  261. private int
  262. zwritehexstring_continue(i_ctx_t *i_ctx_p)
  263. {
  264.     os_ptr op = osp;
  265.     int code;
  266.  
  267.     check_type(*op, t_integer);
  268.     if ((op->value.intval & ~1) != 0)
  269.     return_error(e_rangecheck);
  270.     code = zwritehexstring_at(i_ctx_p, op - 1, (uint) op->value.intval);
  271.     if (code >= 0)
  272.     pop(1);
  273.     return code;
  274. }
  275.  
  276. /* <file> <string> readstring <substring> <filled_bool> */
  277. private int zreadstring_continue(P1(i_ctx_t *));
  278. private int
  279. zreadstring_at(i_ctx_t *i_ctx_p, os_ptr op, uint start)
  280. {
  281.     stream *s;
  282.     uint len, rlen;
  283.     int status;
  284.  
  285.     check_read_file(s, op - 1);
  286.     check_write_type(*op, t_string);
  287.     len = r_size(op);
  288.     status = sgets(s, op->value.bytes + start, len - start, &rlen);
  289.     rlen += start;
  290.     switch (status) {
  291.     case EOFC:
  292.     case 0:
  293.         break;
  294.     default:
  295.         return handle_read_status(i_ctx_p, status, op - 1, &rlen,
  296.                       zreadstring_continue);
  297.     }
  298.     /*
  299.      * The most recent Adobe specification says that readstring
  300.      * must signal a rangecheck if the string length is zero.
  301.      * I can't imagine the motivation for this, but we emulate it.
  302.      * It's safe to check it here, rather than earlier, because if
  303.      * len is zero, sgets will return 0 immediately with rlen = 0.
  304.      */
  305.     if (len == 0)
  306.     return_error(e_rangecheck);
  307.     r_set_size(op, rlen);
  308.     op[-1] = *op;
  309.     make_bool(op, (rlen == len ? 1 : 0));
  310.     return 0;
  311. }
  312. private int
  313. zreadstring(i_ctx_t *i_ctx_p)
  314. {
  315.     os_ptr op = osp;
  316.  
  317.     return zreadstring_at(i_ctx_p, op, 0);
  318. }
  319. /* Continue a readstring operation after a callout. */
  320. /* *op is the index within the string. */
  321. private int
  322. zreadstring_continue(i_ctx_t *i_ctx_p)
  323. {
  324.     os_ptr op = osp;
  325.     int code;
  326.  
  327.     check_type(*op, t_integer);
  328.     if (op->value.intval < 0 || op->value.intval > r_size(op - 1))
  329.     return_error(e_rangecheck);
  330.     code = zreadstring_at(i_ctx_p, op - 1, (uint) op->value.intval);
  331.     if (code >= 0)
  332.     pop(1);
  333.     return code;
  334. }
  335.  
  336. /* <file> <string> writestring - */
  337. private int
  338. zwritestring(i_ctx_t *i_ctx_p)
  339. {
  340.     os_ptr op = osp;
  341.     stream *s;
  342.     int status;
  343.  
  344.     check_write_file(s, op - 1);
  345.     check_read_type(*op, t_string);
  346.     status = write_string(op, s);
  347.     if (status >= 0) {
  348.     pop(2);
  349.     return 0;
  350.     }
  351.     return handle_write_status(i_ctx_p, status, op - 1, NULL, zwritestring);
  352. }
  353.  
  354. /* <file> <string> readline <substring> <bool> */
  355. private int zreadline(P1(i_ctx_t *));
  356. private int zreadline_continue(P1(i_ctx_t *));
  357.  
  358. /*
  359.  * We could handle readline the same way as readstring,
  360.  * except for the anomalous situation where we get interrupted
  361.  * between the CR and the LF of an end-of-line marker.
  362.  * We hack around this in the following way: if we get interrupted
  363.  * before we've read any characters, we just restart the readline;
  364.  * if we get interrupted at any other time, we use readline_continue;
  365.  * we use start=0 (which we have just ruled out as a possible start value
  366.  * for readline_continue) to indicate interruption after the CR.
  367.  */
  368. private int
  369. zreadline_at(i_ctx_t *i_ctx_p, os_ptr op, uint count, bool in_eol)
  370. {
  371.     stream *s;
  372.     int status;
  373.     gs_string str;
  374.  
  375.     check_read_file(s, op - 1);
  376.     check_write_type(*op, t_string);
  377.     str.data = op->value.bytes;
  378.     str.size = r_size(op);
  379.     status = zreadline_from(s, &str, NULL, &count, &in_eol);
  380.     switch (status) {
  381.     case 0:
  382.     case EOFC:
  383.         break;
  384.     case 1:
  385.         return_error(e_rangecheck);
  386.     default:
  387.         if (count == 0 && !in_eol)
  388.         return handle_read_status(i_ctx_p, status, op - 1, NULL,
  389.                       zreadline);
  390.         else {
  391.         if (in_eol) {
  392.             r_set_size(op, count);
  393.             count = 0;
  394.         }
  395.         return handle_read_status(i_ctx_p, status, op - 1, &count,
  396.                       zreadline_continue);
  397.         }
  398.     }
  399.     r_set_size(op, count);
  400.     op[-1] = *op;
  401.     make_bool(op, status == 0);
  402.     return 0;
  403. }
  404. private int
  405. zreadline(i_ctx_t *i_ctx_p)
  406. {
  407.     os_ptr op = osp;
  408.  
  409.     return zreadline_at(i_ctx_p, op, 0, false);
  410. }
  411. /* Continue a readline operation after a callout. */
  412. /* *op is the index within the string, or 0 for an interrupt after a CR. */
  413. private int
  414. zreadline_continue(i_ctx_t *i_ctx_p)
  415. {
  416.     os_ptr op = osp;
  417.     uint size = r_size(op - 1);
  418.     uint start;
  419.     int code;
  420.  
  421.     check_type(*op, t_integer);
  422.     if (op->value.intval < 0 || op->value.intval > size)
  423.     return_error(e_rangecheck);
  424.     start = (uint) op->value.intval;
  425.     code = (start == 0 ? zreadline_at(i_ctx_p, op - 1, size, true) :
  426.         zreadline_at(i_ctx_p, op - 1, start, false));
  427.     if (code >= 0)
  428.     pop(1);
  429.     return code;
  430. }
  431.  
  432. /* Internal readline routine. */
  433. /* Returns a stream status value, or 1 if we overflowed the string. */
  434. /* This is exported for %lineedit. */
  435. int
  436. zreadline_from(stream *s, gs_string *buf, gs_memory_t *bufmem,
  437.            uint *pcount, bool *pin_eol)
  438. {
  439.     sreadline_proc((*readline));
  440.  
  441.     if (zis_stdin(s))
  442.     readline = gp_readline;
  443.     else
  444.     readline = sreadline;
  445.     return readline(s, NULL, NULL /*WRONG*/, NULL, buf, bufmem,
  446.             pcount, pin_eol, zis_stdin);
  447. }
  448.  
  449. /* <file> bytesavailable <int> */
  450. private int
  451. zbytesavailable(i_ctx_t *i_ctx_p)
  452. {
  453.     os_ptr op = osp;
  454.     stream *s;
  455.     long avail;
  456.  
  457.     check_read_file(s, op);
  458.     switch (savailable(s, &avail)) {
  459.     default:
  460.         return_error(e_ioerror);
  461.     case EOFC:
  462.         avail = -1;
  463.     case 0:
  464.         ;
  465.     }
  466.     make_int(op, avail);
  467.     return 0;
  468. }
  469.  
  470. /* - flush - */
  471. int
  472. zflush(i_ctx_t *i_ctx_p)
  473. {
  474.     stream *s;
  475.     int code = zget_stdout(i_ctx_p, &s);
  476.  
  477.     if (code < 0)
  478.     return code;
  479.     sflush(s);
  480.     return 0;
  481. }
  482.  
  483. /* <file> flushfile - */
  484. private int
  485. zflushfile(i_ctx_t *i_ctx_p)
  486. {
  487.     os_ptr op = osp;
  488.     stream *s;
  489.     int status;
  490.  
  491.     check_type(*op, t_file);
  492.     /*
  493.      * We think flushfile is a no-op on closed input files, but causes an
  494.      * error on closed output files.
  495.      */
  496.     if (file_is_invalid(s, op)) {
  497.     if (r_has_attr(op, a_write))
  498.         return_error(e_invalidaccess);
  499.     pop(1);
  500.     return 0;
  501.     }
  502.     status = sflush(s);
  503.     if (status == 0 || status == EOFC) {
  504.     pop(1);
  505.     return 0;
  506.     }
  507.     return
  508.     (s_is_writing(s) ?
  509.      handle_write_status(i_ctx_p, status, op, NULL, zflushfile) :
  510.      handle_read_status(i_ctx_p, status, op, NULL, zflushfile));
  511. }
  512.  
  513. /* <file> resetfile - */
  514. private int
  515. zresetfile(i_ctx_t *i_ctx_p)
  516. {
  517.     os_ptr op = osp;
  518.     stream *s;
  519.  
  520.     /* According to Adobe, resetfile is a no-op on closed files. */
  521.     check_type(*op, t_file);
  522.     if (file_is_valid(s, op))
  523.     sreset(s);
  524.     pop(1);
  525.     return 0;
  526. }
  527.  
  528. /* <string> print - */
  529. private int
  530. zprint(i_ctx_t *i_ctx_p)
  531. {
  532.     os_ptr op = osp;
  533.     stream *s;
  534.     int status;
  535.     ref rstdout;
  536.     int code;
  537.  
  538.     check_read_type(*op, t_string);
  539.     code = zget_stdout(i_ctx_p, &s);
  540.     if (code < 0)
  541.     return code;
  542.     status = write_string(op, s);
  543.     if (status >= 0) {
  544.     pop(1);
  545.     return 0;
  546.     }
  547.     /* Convert print to writestring on the fly. */
  548.     make_stream_file(&rstdout, s, "w");
  549.     code = handle_write_status(i_ctx_p, status, &rstdout, NULL,
  550.                    zwritestring);
  551.     if (code != o_push_estack)
  552.     return code;
  553.     push(1);
  554.     *op = op[-1];
  555.     op[-1] = rstdout;
  556.     return code;
  557. }
  558.  
  559. /* <bool> echo - */
  560. private int
  561. zecho(i_ctx_t *i_ctx_p)
  562. {
  563.     os_ptr op = osp;
  564.  
  565.     check_type(*op, t_boolean);
  566.     /****** NOT IMPLEMENTED YET ******/
  567.     pop(1);
  568.     return 0;
  569. }
  570.  
  571. /* ------ Level 2 extensions ------ */
  572.  
  573. /* <file> fileposition <int> */
  574. private int
  575. zfileposition(i_ctx_t *i_ctx_p)
  576. {
  577.     os_ptr op = osp;
  578.     stream *s;
  579.  
  580.     check_file(s, op);
  581.     /*
  582.      * The PLRM says fileposition must give an error for non-seekable
  583.      * streams.
  584.      */
  585.     if (!s_can_seek(s))
  586.     return_error(e_ioerror);
  587.     make_int(op, stell(s));
  588.     return 0;
  589. }
  590. /* <file> .fileposition <int> */
  591. private int
  592. zxfileposition(i_ctx_t *i_ctx_p)
  593. {
  594.     os_ptr op = osp;
  595.     stream *s;
  596.  
  597.     check_file(s, op);
  598.     /*
  599.      * This version of fileposition doesn't give the error, so we can
  600.      * use it to get the position of string or procedure streams.
  601.      */
  602.     make_int(op, stell(s));
  603.     return 0;
  604. }
  605.  
  606. /* <file> <int> setfileposition - */
  607. private int
  608. zsetfileposition(i_ctx_t *i_ctx_p)
  609. {
  610.     os_ptr op = osp;
  611.     stream *s;
  612.  
  613.     check_file(s, op - 1);
  614.     check_type(*op, t_integer);
  615.     if (sseek(s, op->value.intval) < 0)
  616.     return_error(e_ioerror);
  617.     pop(2);
  618.     return 0;
  619. }
  620.  
  621. /* ------ Non-standard extensions ------ */
  622.  
  623. /* <file> .filename <string> true */
  624. /* <file> .filename false */
  625. private int
  626. zfilename(i_ctx_t *i_ctx_p)
  627. {
  628.     os_ptr op = osp;
  629.     stream *s;
  630.     gs_const_string fname;
  631.     byte *str;
  632.  
  633.     check_file(s, op);
  634.     if (sfilename(s, &fname) < 0) {
  635.     make_false(op);
  636.     return 0;
  637.     }
  638.     check_ostack(1);
  639.     str = ialloc_string(fname.size, "filename");
  640.     if (str == 0)
  641.     return_error(e_VMerror);
  642.     memcpy(str, fname.data, fname.size);
  643.     push(1);            /* can't fail */
  644.     make_const_string(op - 1, a_all, fname.size, str);
  645.     make_true(op);
  646.     return 0;
  647. }
  648.  
  649. /* <file> .isprocfilter <bool> */
  650. private int
  651. zisprocfilter(i_ctx_t *i_ctx_p)
  652. {
  653.     os_ptr op = osp;
  654.     stream *s;
  655.  
  656.     check_file(s, op);
  657.     while (s->strm != 0)
  658.     s = s->strm;
  659.     make_bool(op, s_is_proc(s));
  660.     return 0;
  661. }
  662.  
  663. /* <file> <string> .peekstring <substring> <filled_bool> */
  664. private int
  665. zpeekstring(i_ctx_t *i_ctx_p)
  666. {
  667.     os_ptr op = osp;
  668.     stream *s;
  669.     uint len, rlen;
  670.  
  671.     check_read_file(s, op - 1);
  672.     check_write_type(*op, t_string);
  673.     len = r_size(op);
  674.     while ((rlen = sbufavailable(s)) < len) {
  675.     int status = s->end_status;
  676.  
  677.     /*
  678.      * The following is a HACK.  It should reallocate the buffer to hold
  679.      * at least len bytes.  However, this raises messy problems about
  680.      * which allocator to use and how it should interact with restore.
  681.      */
  682.     if (len >= s->bsize)
  683.         return_error(e_rangecheck);
  684.     switch (status) {
  685.     case EOFC:
  686.         break;
  687.     case 0:
  688.         s_process_read_buf(s);
  689.         continue;
  690.     default:
  691.         return handle_read_status(i_ctx_p, status, op - 1, &rlen,
  692.                       zpeekstring);
  693.     }
  694.     break;
  695.     }
  696.     if (rlen > len)
  697.     rlen = len;
  698.     /* Don't remove the data from the buffer. */
  699.     memcpy(op->value.bytes, sbufptr(s), rlen);
  700.     r_set_size(op, rlen);
  701.     op[-1] = *op;
  702.     make_bool(op, (rlen == len ? 1 : 0));
  703.     return 0;
  704. }
  705.  
  706. /* <file> <int> .unread - */
  707. private int
  708. zunread(i_ctx_t *i_ctx_p)
  709. {
  710.     os_ptr op = osp;
  711.     stream *s;
  712.     ulong ch;
  713.  
  714.     check_read_file(s, op - 1);
  715.     check_type(*op, t_integer);
  716.     ch = op->value.intval;
  717.     if (ch > 0xff)
  718.     return_error(e_rangecheck);
  719.     if (sungetc(s, (byte) ch) < 0)
  720.     return_error(e_ioerror);
  721.     pop(2);
  722.     return 0;
  723. }
  724.  
  725. /* <file> <obj> <==flag> .writecvp - */
  726. private int zwritecvp_continue(P1(i_ctx_t *));
  727. private int
  728. zwritecvp_at(i_ctx_t *i_ctx_p, os_ptr op, uint start, bool first)
  729. {
  730.     stream *s;
  731.     byte str[100];        /* arbitrary */
  732.     ref rstr;
  733.     const byte *data = str;
  734.     uint len;
  735.     int code, status;
  736.  
  737.     check_write_file(s, op - 2);
  738.     check_type(*op, t_integer);
  739.     code = obj_cvp(op - 1, str, sizeof(str), &len, (int)op->value.intval,
  740.            start, imemory);
  741.     if (code == e_rangecheck) {
  742.     code = obj_string_data(op - 1, &data, &len);
  743.     if (len < start)
  744.         return_error(e_rangecheck);
  745.     data += start;
  746.     len -= start;
  747.     }
  748.     if (code < 0)
  749.     return code;
  750.     r_set_size(&rstr, len);
  751.     rstr.value.const_bytes = data;
  752.     status = write_string(&rstr, s);
  753.     switch (status) {
  754.     default:
  755.         return_error(e_ioerror);
  756.     case 0:
  757.         break;
  758.     case INTC:
  759.     case CALLC:
  760.         len = start + len - r_size(&rstr);
  761.         if (!first)
  762.         --osp;        /* pop(1) without affecting op */
  763.         return handle_write_status(i_ctx_p, status, op - 2, &len,
  764.                        zwritecvp_continue);
  765.     }
  766.     if (code == 1) {
  767.     if (first)
  768.         check_ostack(1);
  769.     push_op_estack(zwritecvp_continue);
  770.     if (first)
  771.         push(1);
  772.     make_int(osp, start + len);
  773.     return o_push_estack;
  774.     }
  775.     if (first)            /* zwritecvp */
  776.     pop(3);
  777.     else            /* zwritecvp_continue */
  778.     pop(4);
  779.     return 0;
  780. }
  781. private int
  782. zwritecvp(i_ctx_t *i_ctx_p)
  783. {
  784.     return zwritecvp_at(i_ctx_p, osp, 0, true);
  785. }
  786. /* Continue a .writecvp after a callout. */
  787. /* *op is the index within the string. */
  788. private int
  789. zwritecvp_continue(i_ctx_t *i_ctx_p)
  790. {
  791.     os_ptr op = osp;
  792.  
  793.     check_type(*op, t_integer);
  794.     if (op->value.intval != (uint) op->value.intval)
  795.     return_error(e_rangecheck);
  796.     return zwritecvp_at(i_ctx_p, op - 1, (uint) op->value.intval, false);
  797. }
  798.  
  799. /* ------ Initialization procedure ------ */
  800.  
  801. /* We need to split the table because of the 16-element limit. */
  802. const op_def zfileio1_op_defs[] = {
  803.     {"1bytesavailable", zbytesavailable},
  804.     {"1closefile", zclosefile},
  805.         /* currentfile is in zcontrol.c */
  806.     {"1echo", zecho},
  807.     {"1.filename", zfilename},
  808.     {"1.fileposition", zxfileposition},
  809.     {"1fileposition", zfileposition},
  810.     {"0flush", zflush},
  811.     {"1flushfile", zflushfile},
  812.     {"1.isprocfilter", zisprocfilter},
  813.     {"2.peekstring", zpeekstring},
  814.     {"1print", zprint},
  815.     {"1read", zread},
  816.     {"2readhexstring", zreadhexstring},
  817.     {"2readline", zreadline},
  818.     {"2readstring", zreadstring},
  819.     op_def_end(0)
  820. };
  821. const op_def zfileio2_op_defs[] = {
  822.     {"1resetfile", zresetfile},
  823.     {"2setfileposition", zsetfileposition},
  824.     {"2.unread", zunread},
  825.     {"2write", zwrite},
  826.     {"3.writecvp", zwritecvp},
  827.     {"2writehexstring", zwritehexstring},
  828.     {"2writestring", zwritestring},
  829.         /* Internal operators */
  830.     {"3%zreadhexstring_continue", zreadhexstring_continue},
  831.     {"3%zreadline_continue", zreadline_continue},
  832.     {"3%zreadstring_continue", zreadstring_continue},
  833.     {"4%zwritecvp_continue", zwritecvp_continue},
  834.     {"3%zwritehexstring_continue", zwritehexstring_continue},
  835.     op_def_end(0)
  836. };
  837.  
  838. /* ------ Non-operator routines ------ */
  839.  
  840. /* Switch a file open for read/write access but currently in write mode */
  841. /* to read mode. */
  842. int
  843. file_switch_to_read(const ref * op)
  844. {
  845.     stream *s = fptr(op);
  846.  
  847.     if (s->write_id != r_size(op) || s->file == 0)    /* not valid */
  848.     return_error(e_invalidaccess);
  849.     if (sswitch(s, false) < 0)
  850.     return_error(e_ioerror);
  851.     s->read_id = s->write_id;    /* enable reading */
  852.     s->write_id = 0;        /* disable writing */
  853.     return 0;
  854. }
  855.  
  856. /* Switch a file open for read/write access but currently in read mode */
  857. /* to write mode. */
  858. int
  859. file_switch_to_write(const ref * op)
  860. {
  861.     stream *s = fptr(op);
  862.  
  863.     if (s->read_id != r_size(op) || s->file == 0)    /* not valid */
  864.     return_error(e_invalidaccess);
  865.     if (sswitch(s, true) < 0)
  866.     return_error(e_ioerror);
  867.     s->write_id = s->read_id;    /* enable writing */
  868.     s->read_id = 0;        /* disable reading */
  869.     return 0;
  870. }
  871.  
  872. /* ------ Internal routines ------ */
  873.  
  874. /* Write a string on a file.  The file and string have been validated. */
  875. /* If the status is INTC or CALLC, updates the string on the o-stack. */
  876. private int
  877. write_string(ref * op, stream * s)
  878. {
  879.     const byte *data = op->value.const_bytes;
  880.     uint len = r_size(op);
  881.     uint wlen;
  882.     int status = sputs(s, data, len, &wlen);
  883.  
  884.     switch (status) {
  885.     case INTC:
  886.     case CALLC:
  887.         op->value.const_bytes = data + wlen;
  888.         r_set_size(op, len - wlen);
  889.         /* falls through */
  890.     default:        /* 0, EOFC, ERRC */
  891.         return status;
  892.     }
  893. }
  894.  
  895. /*
  896.  * Look for a stream error message that needs to be copied to
  897.  * $error.errorinfo, if any.
  898.  */
  899. private int
  900. copy_error_string(i_ctx_t *i_ctx_p, const ref *fop)
  901. {
  902.     stream *s;
  903.  
  904.     for (s = fptr(fop); s->strm != 0 && s->state->error_string[0] == 0;)
  905.     s = s->strm;
  906.     if (s->state->error_string[0]) {
  907.     int code = gs_errorinfo_put_string(i_ctx_p, s->state->error_string);
  908.  
  909.     if (code < 0)
  910.         return code;
  911.     s->state->error_string[0] = 0; /* just do it once */
  912.     }
  913.     return_error(e_ioerror);
  914. }
  915.  
  916. /* Handle an exceptional status return from a read stream. */
  917. /* fop points to the ref for the stream. */
  918. /* ch may be any stream exceptional value. */
  919. /* Return 0, 1 (EOF), o_push_estack, or an error. */
  920. private int
  921. handle_read_status(i_ctx_t *i_ctx_p, int ch, const ref * fop,
  922.            const uint * pindex, op_proc_t cont)
  923. {
  924.     switch (ch) {
  925.     default:        /* error */
  926.         return copy_error_string(i_ctx_p, fop);
  927.     case EOFC:
  928.         return 1;
  929.     case INTC:
  930.     case CALLC:
  931.         if (pindex) {
  932.         ref index;
  933.  
  934.         make_int(&index, *pindex);
  935.         return s_handle_read_exception(i_ctx_p, ch, fop, &index, 1,
  936.                            cont);
  937.         } else
  938.         return s_handle_read_exception(i_ctx_p, ch, fop, NULL, 0,
  939.                            cont);
  940.     }
  941. }
  942.  
  943. /* Handle an exceptional status return from a write stream. */
  944. /* fop points to the ref for the stream. */
  945. /* ch may be any stream exceptional value. */
  946. /* Return 0, 1 (EOF), o_push_estack, or an error. */
  947. private int
  948. handle_write_status(i_ctx_t *i_ctx_p, int ch, const ref * fop,
  949.             const uint * pindex, op_proc_t cont)
  950. {
  951.     switch (ch) {
  952.     default:        /* error */
  953.         return copy_error_string(i_ctx_p, fop);
  954.     case EOFC:
  955.         return 1;
  956.     case INTC:
  957.     case CALLC:
  958.         if (pindex) {
  959.         ref index;
  960.  
  961.         make_int(&index, *pindex);
  962.         return s_handle_write_exception(i_ctx_p, ch, fop, &index, 1,
  963.                         cont);
  964.         } else
  965.         return s_handle_write_exception(i_ctx_p, ch, fop, NULL, 0,
  966.                         cont);
  967.     }
  968. }
  969.